package eyer.jvm;

import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.SocketException;
import java.util.Date;
import java.util.Properties;

import eyer.utils.IPUtils;

public class JVMInfo implements JVMInfoMBean {
    private static JVMInfo instance = new JVMInfo();
    private RuntimeMXBean runtimeMXBean;
    private ClassLoadingMXBean classLoadingMXBean;
    private CompilationMXBean compilationMXBean;
    private Properties properties;
    private String inputArguments;

    public static JVMInfo getInstance() {
        return instance;
    }

    private int availableProcessors = 0;
    private String pid;

    private JVMInfo() {
        this.classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
        this.compilationMXBean = ManagementFactory.getCompilationMXBean();
        this.runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        this.properties = System.getProperties();
    }

    private String getSystemProperty(String key) {
        return this.properties.getProperty(key);
    }

    public Date getStartTime() {
        return new Date(this.runtimeMXBean.getStartTime());
    }

    public String getJVM() {
        return this.runtimeMXBean.getVmName() + " (" + this.runtimeMXBean.getVmVersion() + ", "
                + getSystemProperty("java.vm.info") + ")";
    }

    public String getJavaVersion() {
        return getSystemProperty("java.version") + "[eyer.jshot:" + "1.0.0" + "]";
    }

    public String getPID() {
        if (null == this.pid) {
            this.pid = this.runtimeMXBean.getName().split("@")[0];
        }
        return this.pid;
    }

    public String getInputArguments() {
        if (null == this.inputArguments) {
            this.inputArguments = this.runtimeMXBean.getInputArguments().toString();
        }
        return this.inputArguments;
    }

    public String getJavaHome() {
        return getSystemProperty("java.home");
    }

    public String getArch() {
        return getSystemProperty("os.arch");
    }

    public String getOSName() {
        return getSystemProperty("os.name");
    }

    public String getOSVersion() {
        return getSystemProperty("os.version");
    }

    public String getJavaSpecificationVersion() {
        return getSystemProperty("java.specification.version");
    }

    public String getJavaLibraryPath() {
        return getSystemProperty("java.library.path");
    }

    public String getFileEncode() {
        return getSystemProperty("file.encoding");
    }

    public int getAvailableProcessors() {
        if (this.availableProcessors == 0) {
            this.availableProcessors = Runtime.getRuntime().availableProcessors();
        }
        return this.availableProcessors;
    }

    public int getLoadedClassCount() {
        return this.classLoadingMXBean.getLoadedClassCount();
    }

    public long getTotalLoadedClassCount() {
        return this.classLoadingMXBean.getTotalLoadedClassCount();
    }

    public long getUnloadedClassCount() {
        return this.classLoadingMXBean.getUnloadedClassCount();
    }

    public long getTotalCompilationTime() {
        return this.compilationMXBean.getTotalCompilationTime();
    }

    public String getHostname() {
        return IPUtils.getLocalHostName();
    }

    public String getLocalIP() {
        try {
            return IPUtils.getAllIpv4NoLoopbackAddresses().toString();
        } catch (SocketException e) {
            return null;
        }
    }
}
